﻿#pragma once

#include "Asset/Asset.h"
#include "Render/BlockVertex.h"
#include "Util/Hash.h"

struct BlockElementRotateInfo
{
  glm::vec3 origin{0.f};
  glm::vec3 axis{0.f};
  float angle{0.f};
};

struct BlockElementFaceInfo
{
  glm::ivec4 uv{0, 0, 16, 16};
  std::string texture;

  // 用于计算
  glm::vec3 pA{0.f};
  glm::vec3 pB{0.f};
  glm::vec3 pC{0.f};
  glm::vec3 pD{0.f};

  glm::vec3 normal{0.f};
  float distance{0.f}; // 平面方程的d

  glm::vec3 GetIntersectPoint(const glm::vec3 &start, const glm::vec3 &end) const;
  bool IsInside(const glm::vec3 &point) const;
};

struct BlockElement
{
  glm::vec3 from;
  glm::vec3 to;
  BlockElementRotateInfo rotation;
  std::unordered_map<std::string, BlockElementFaceInfo> faces;

  bool IsRayIntersect(const glm::vec3 &start, const glm::vec3 &end) const;
};

class BlockModel : public Asset
{
public:
  BlockModel(const std::string &path);

  void LoadFromFile(const std::string &path);
  std::vector<BlockElement> &GetElements() { return elements; }
  std::vector<BlockVertex> &CacheVertices();
  const std::vector<BlockVertex> &GetVertices() const;
  std::vector<BlockVertex> &GetVerticesFromDirection(const glm::ivec3 &offset);
  std::vector<BlockVertex> GetVerticesByPos(glm::ivec3 pos);

  bool IsPointInElements(const glm::vec3 &relativePoint) const;
  bool IsRayIntersectElements(const glm::vec3 &start, const glm::vec3 &end) const;

public:
  bool isAmbientOcclusion{true};
  std::unordered_map<std::string, std::string> textures;
  std::vector<BlockElement> elements;

private:
  std::vector<BlockVertex> m_cachedVertices;
  std::unordered_map<glm::ivec3, std::vector<BlockVertex>, Util::HashIVec3> m_directionVertices;
};